

#ifndef RTRL_H
#define	RTRL_H

#include <selforg/matrix.h>
#include <selforg/controller_misc.h>
#include <cmath>
#include <vector>
using namespace matrix;
using namespace std;

/** 
 * File:   rtrl.h
 * 
 * Class that implements the Real Time Recurrent Learning (RTRL) rule in 
 * Recurrent Neural Networks as presented in section 3.1.1 of the thesis.
 * 
 * RTRL is a gradient descent based algorithm that recurrently calculates
 * the sensitivity of output nodes on changes of weights that occur 
 * in the RNN     
 * 
 * @author:  Athanasios Polydoros
 * @version: 1.0
 * Created on 25 June 2013, 19:36
 */
class RTRL {
public:
    /**
     * Class constructor that initialise the members of class. Has to be called
     * in the controller's init method.
     * 
     * @param num_Sensors The number of robot sensors, used as network's outputs
     * @param num_Motors  The number of motors, used as inputs
     */
   RTRL(int num_Sensors, int num_Motors);
    
    /**
     * Class destructor
     */
    virtual ~RTRL();
    
    /**
     * Sets the desired output of the network. This method is called in 
     * controler's method : learn
     * 
     * @param fut_sensor the robot's sensory values 
     */
    void setDesiredOut (Matrix fut_sensor);
    
    /**
     * Set the current inputs of the network
     * 
     * @param motors The values of robot's motors   
     */
    void setState(Matrix motors);
    
    /**
    *  Predicts the future sensor values based on the current motor commands (inputs).
     * 
     * It consists of two steps.
     * 1. Calculate activations ( @see simulateNet() )
     * 2. Update weights based on error (@see updateWeights() )
     * @return Matrix that contains the predicted sensory values. 
    */
     Matrix predict();
     
     /**
      * Calculate the jacobian matrix of the network.
      * The derivative of outputs wrt inputs.
      * Should be called after activation of network
      * 
      * @param the input nodes values 
      * @return MxM Jacobian matrix
      */
     Matrix getModelMatrix (Matrix input);
     
    double learningRate; /**< The learning rate of the algirith set 0.01 */
    
   
    
private:
    
    /**
     *  Calculate the network's activations
     * 
     * @return Matrix with the values of each node activation
     */
    Matrix simulateNet();
    
    /**
     * Calculate the sensitivity of output nodes.
     * 
     * @param updatedNodes Matrix of the activated nodes values
     * @param nodesValue Values of nodes before their activation
     */
    void getNodeSensitivity(Matrix updatedNodes,Matrix nodesValue);
    
    /**
     *The squashing function of the network. the hyperbolic
     * tangent used (tanh)
     * 
     * @param node the value that will be mapped
     */
    static double squash(double node);
    
    /**
     *The derivative of squashing function of the network
     * 
     * @param node the value that will be mapped
     */
    static double squash_derivative(double node);
    
    /**
     *Update weights based on gradient descent and sensitivity.
     * @param the nodes activations
     */
    void updateWeights(Matrix updatedNodes);
    
    /**
     *The Kronnecker delta 
     * @return 1 if i=0 , otherwise 0
     */
    int kronneckerDelta (int i, int k);
    Matrix nodeState;  /**< The values of nodes before activation of the network*/
    int numInputNodes; /**< The number of input nodes*/
    int numReservoirNodes; /**< The number of reservoir nodes*/
    int numOutputNodes;  /**< The number of output nodes*/
    
    Matrix outputState; /**< The values of the output nodes*/
    Matrix weights;     /**< Matrix containing the weights ofthe network*/
   
    vector <Matrix> nodeSensitivity; /**< Vector which contains one matrix per output node, the sensitivity of each output node */
    Matrix desiredSens; /** The desired output of the network, true sensor values*/
    
    
};

#endif	/* RTRL_H */

